home *** CD-ROM | disk | FTP | other *** search
/ Light ROM 1 / LIGHT-ROM 1 (Amiga Library Services)(1994).iso / ffdisks / d983.lha / TitleClock / TitleClock.c < prev    next >
C/C++ Source or Header  |  1994-04-04  |  16KB  |  729 lines

  1. /*
  2. **  TitleClock - throw up a clock in the top right
  3. **
  4. **  Copyright ©1992-94 by Anders Hammarquist, permission granted for
  5. **  non-commercial use and distribution. See documentation for further
  6. **  information.
  7. **
  8. **  $Id: TitleClock.c,v 3.3 94/02/12 16:08:52 Viking Exp Locker: Viking $
  9. **
  10. **  $Revision: 3.3 $
  11. **  $Date: 94/02/12 16:08:52 $
  12. **
  13. */
  14.  
  15. #define __USE_SYSBASE
  16.  
  17. #include <dos/datetime.h>
  18. #include <dos/dos.h>
  19. #include <exec/memory.h>
  20. #include <exec/execbase.h>
  21. #include <exec/devices.h>
  22. #include <exec/libraries.h>
  23. #include <intuition/intuition.h>
  24. #include <intuition/intuitionbase.h>
  25. #include <graphics/gfx.h>
  26. #include <libraries/commodities.h>
  27. #include <devices/timer.h>
  28. #include <proto/exec.h>
  29. #include <proto/dos.h>
  30. #include <proto/graphics.h>
  31. #include <proto/intuition.h>
  32. #include <proto/icon.h>
  33. #include <proto/utility.h>
  34. #include <proto/commodities.h>
  35. #include <proto/timer.h>
  36. #include <workbench/workbench.h>
  37. #include <workbench/startup.h>
  38. #include "titleclock_protos.h"
  39.  
  40. #include <libraries/locale.h>
  41. #include <proto/locale.h>
  42.  
  43. /* Stuff */
  44. #define MAXCLOCKLEN 256
  45. #define CLOCKOFFSET 5 /* Number of pixels between screen depth gadget */
  46.               /* and clock text */
  47. #define TEMPLATE "UPDATE/N/K,SHOWDATE/S,SHOWDAY/S,SHORTDAY/S,SHOWSECS/S,FORMAT/K,DATEFORMAT/K,PUBSCREEN/K,SCREENPAT/K,FRONTSCREEN/S,DEFSCREEN/S,CX_PRIORITY/N/K"
  48. enum ArgsEnum
  49. {
  50.     UPDATE,
  51.     SHOWDATE,
  52.     SHOWDAY,
  53.     SHORTDAY,
  54.     SHOWSECS,
  55.     FORMAT,
  56.     DATEFORMAT,
  57.     PUBSCREEN,
  58.     SCREENPAT,
  59.     FRONTSCREEN,
  60.     DEFSCREEN,
  61.     CX_PRI,
  62.     NUMARGS
  63. };
  64.  
  65. #ifndef BARDETAILPEN
  66. #define BARDETAILPEN    (0x0009)
  67. #define BARBLOCKPEN    (0x000A)
  68. #endif
  69.  
  70. #define min(a,b) ((a)>(b)?(b):(a))
  71. #define max(a,b) ((a)<(b)?(b):(a))
  72. #define tolower(a) ((a)|0x20) /* Quick-and-dirty */
  73. #define isnum(a) (((a)>0x2F)&&((a)<0x3A))
  74.  
  75. /* From sysiclass docs */
  76. #define LOWDEPTHWIDTH 17
  77. #define HIDEPTHWIDTH  23
  78.  
  79. /* More stuff */
  80. static struct RastPort *MyRPort=NULL;
  81. static struct BitMap   *MyBitMap=NULL;
  82.  
  83. struct ExecBase     *SysBase;
  84. struct DosLibrary    *DOSBase;
  85. struct GfxBase        *GfxBase;
  86. struct IntuitionBase    *IntuitionBase;
  87. struct Library        *UtilityBase;
  88. struct Library        *CxBase;
  89. struct Library        *IconBase;
  90. struct Library        *TimerBase;
  91. struct LocaleBase    *LocaleBase;
  92.  
  93. struct Locale        *Locale;
  94.  
  95. static const char *Ver="$VER: TitleClock 3.3 (12.2.94)";
  96.  
  97. static struct NewBroker newbrok =
  98. {
  99.     NB_VERSION,
  100.     "TitleClock",
  101.     "TitleClock",
  102.     "Displays clock in screen titlebar",
  103.     NBU_UNIQUE|NBU_NOTIFY,
  104.     0,
  105.     0,
  106.     0,
  107.     0
  108. };
  109.  
  110. static LONG Update=1;
  111. static LONG Fmt=FORMAT_DOS;
  112. static LONG Args[NUMARGS] = { (LONG)&Update, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (LONG)&(newbrok.nb_Pri)};
  113. static int LeftEdge;
  114.  
  115. static char *PubPat=NULL, *ScrPat=NULL;
  116.  
  117. static struct timerequest *TimerIO=NULL;
  118.  
  119. static BOOL TimerPending=0, WildPub;
  120.  
  121. /* Da main routine */
  122. int __saveds TitleClock(void)
  123. {
  124.     struct Process *MyProc;
  125.     struct WBStartup *WBs=NULL;
  126.     struct DiskObject *Do=NULL;
  127.     struct MsgPort  *CXPort=NULL, *TimerPort=NULL;
  128.     struct RDArgs     *rdargs=NULL;
  129.     CxObj *Broker=NULL;
  130.     BOOL TimerFail=TRUE;
  131.     int CXSig, TimerSig;
  132.     long sig;
  133.     CxMsg *CXMsg;
  134.  
  135.     /* set up ExecBase */
  136.     SysBase = *((struct ExecBase **)(4L));
  137.  
  138.     if(!((MyProc=(struct Process *)FindTask(NULL))->pr_CLI))
  139.     {
  140.     /* Started from WB */
  141.  
  142.     /* Get Message */
  143.     WaitPort(&(MyProc->pr_MsgPort));
  144.     WBs=(struct WBStartup *)GetMsg(&(MyProc->pr_MsgPort));
  145.     }
  146.  
  147.     /* Check version */
  148.     if(SysBase->LibNode.lib_Version<37) /* Too Old */
  149.     goto exit;
  150.  
  151.     /* Open needed libraries */
  152.     DOSBase=(struct DosLibrary *)OpenLibrary("dos.library",37);
  153.     GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",37);
  154.     IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",37);
  155.     UtilityBase=OpenLibrary("utility.library",37);
  156.     CxBase=OpenLibrary("commodities.library",37);
  157.     IconBase=OpenLibrary("icon.library",37);
  158.     LocaleBase=(struct LocaleBase *)OpenLibrary("locale.library",38);
  159.  
  160.     if(!(DOSBase&&GfxBase&&IntuitionBase&&UtilityBase&&CxBase&&IconBase))
  161.     /* didn't open */
  162.     goto cleanup;
  163.  
  164.     if(LocaleBase)
  165.     Locale=OpenLocale(NULL);
  166.  
  167.     if(WBs)
  168.     {
  169.         BPTR oldLock;
  170.       
  171.     oldLock=CurrentDir(WBs->sm_ArgList[0].wa_Lock);
  172.  
  173.     if(Do=GetDiskObject(WBs->sm_ArgList[0].wa_Name))
  174.     {
  175.         char *ToolValue;
  176.  
  177.         /* Update */
  178.         if(ToolValue=FindToolType(Do->do_ToolTypes,"UPDATE"))
  179.         StrToLong(ToolValue,&Update);
  180.  
  181.         /* Showdate */
  182.         Args[SHOWDATE]=(long)FindToolType(Do->do_ToolTypes,"SHOWDATE");
  183.  
  184.         /* Showday */
  185.         Args[SHOWDAY]=(long)FindToolType(Do->do_ToolTypes,"SHOWDAY");
  186.  
  187.         /* Shortday */
  188.         Args[SHORTDAY]=(long)FindToolType(Do->do_ToolTypes,"SHORTDAY");
  189.  
  190.         /* Showsecs */
  191.         Args[SHOWSECS]=(long)FindToolType(Do->do_ToolTypes,"SHOWSECS");
  192.  
  193.         /* Format */
  194.         Args[FORMAT]=(long)FindToolType(Do->do_ToolTypes,"FORMAT");
  195.  
  196.         /* DateFormat */
  197.         Args[DATEFORMAT]=(long)FindToolType(Do->do_ToolTypes,"DATEFORMAT");
  198.  
  199.         /* PubScreen */
  200.         Args[PUBSCREEN]=(long)FindToolType(Do->do_ToolTypes,"PUBSCREEN");
  201.  
  202.         /* NonPubScreen */
  203.         Args[SCREENPAT]=(long)FindToolType(Do->do_ToolTypes,"SCREENPAT");
  204.  
  205.         /* FrontScreen */
  206.         Args[FRONTSCREEN]=(long)FindToolType(Do->do_ToolTypes,"FRONTSCREEN");
  207.  
  208.         /* DefScreen */
  209.         Args[DEFSCREEN]=(long)FindToolType(Do->do_ToolTypes,"DEFSCREEN");
  210.  
  211.         /* CX_Priority */
  212.         if(ToolValue=FindToolType(Do->do_ToolTypes,"CX_PRIORITY"))
  213.         StrToLong(ToolValue,&Args[CX_PRI]);
  214.     }
  215.  
  216.     CurrentDir(oldLock);
  217.     }
  218.     else
  219.     if(!(rdargs=ReadArgs(TEMPLATE,Args,NULL)))
  220.     {
  221.         PrintFault(IoErr(),"TitleClock");
  222.         goto cleanup;
  223.     }
  224.  
  225.     newbrok.nb_Pri=*(int *)Args[CX_PRI];
  226.  
  227.     if(Args[FORMAT])
  228.     {
  229.     switch(tolower(((char *)Args[FORMAT])[1]))
  230.     {
  231.         case 'o': /* DOS */
  232.         Fmt=FORMAT_DOS;
  233.         break;
  234.  
  235.         case 'n': /* International */
  236.         Fmt=FORMAT_INT;
  237.         break;
  238.  
  239.         case 'm': /* American */
  240.         Fmt=FORMAT_USA;
  241.         break;
  242.  
  243.         case 'a': /* Canadian */
  244.         Fmt=FORMAT_CDN;
  245.         break;
  246.     }
  247.     }
  248.  
  249.     if(Args[PUBSCREEN])
  250.     {
  251.     int len;
  252.  
  253.     if(PubPat=AllocVec(len=StrLen((char *)Args[PUBSCREEN])*2+2,MEMF_ANY))
  254.     {
  255.         if((WildPub=ParsePattern((char *)Args[PUBSCREEN],PubPat,len))==-1)
  256.         {
  257.         FreeVec(PubPat);
  258.         PubPat=NULL;
  259.         }
  260.     }
  261.  
  262.     }
  263.  
  264.     if(Args[SCREENPAT])
  265.     {
  266.     int len;
  267.  
  268.     if(ScrPat=AllocVec(len=StrLen((char *)Args[SCREENPAT])*2+2,MEMF_ANY))
  269.     {
  270.         if(ParsePattern((char *)Args[SCREENPAT],ScrPat,len)==-1)
  271.         {
  272.         FreeVec(ScrPat);
  273.         ScrPat=NULL;
  274.         }
  275.     }
  276.  
  277.     }
  278.  
  279.     /* Args read */
  280.  
  281.     /* Allocate BitMap and RastPort */
  282.     if(!(MyBitMap=AllocVec(sizeof(struct BitMap),MEMF_CLEAR|MEMF_PUBLIC)))
  283.     goto cleanup;
  284.  
  285.     if(!(MyRPort=AllocVec(sizeof(struct RastPort),MEMF_CLEAR|MEMF_PUBLIC)))
  286.     goto cleanup;
  287.  
  288.     InitRastPort(MyRPort);
  289.     MyRPort->BitMap=MyBitMap;
  290.  
  291.     /* Set up timer.device */
  292.     if(!(TimerPort=CreateMsgPort()))
  293.     goto cleanup;
  294.  
  295.     TimerSig= 1L << TimerPort->mp_SigBit;
  296.  
  297.     if(!(TimerIO=(struct timerequest *)
  298.             CreateIORequest(TimerPort,sizeof(struct timerequest))))
  299.     goto cleanup;
  300.  
  301.     if(TimerFail=OpenDevice("timer.device",UNIT_WAITUNTIL,TimerIO,0))
  302.     goto cleanup;
  303.  
  304.     /* Library pointer */
  305.     TimerBase=TimerIO->tr_node.io_Device;
  306.  
  307.     /* Init timerequest */
  308.     TimerIO->tr_node.io_Command=TR_ADDREQUEST;
  309.     TimerIO->tr_time.tv_micro=0;
  310.  
  311.     if(!(CXPort=CreateMsgPort()))
  312.     goto cleanup;
  313.  
  314.     CXSig   = 1L << CXPort->mp_SigBit;
  315.  
  316.     newbrok.nb_Port=CXPort;
  317.  
  318.     if(!(Broker=CxBroker(&newbrok,NULL)))
  319.     goto cleanup;
  320.  
  321.     ActivateCxObj(Broker,1L);
  322.  
  323.     /* Setup done */
  324.  
  325.     {
  326.     int Abort=0, Enabled=1;
  327.  
  328.     UpdateClk();
  329.  
  330.     while(!Abort)
  331.     {
  332.         sig=Wait(CXSig|TimerSig|SIGBREAKF_CTRL_C);
  333.  
  334.         if(sig&TimerSig)
  335.         {
  336.         if(GetMsg(TimerPort))
  337.         {
  338.             TimerPending--;
  339.             if(Enabled) UpdateClk();
  340.         }
  341.         }
  342.  
  343.         while(CXMsg=(CxMsg *)GetMsg(CXPort))
  344.         {
  345.         const int msgid=CxMsgID(CXMsg);
  346.         const int msgtype=CxMsgType(CXMsg);
  347.  
  348.         ReplyMsg((struct Message *)CXMsg);
  349.  
  350.         if(msgtype==CXM_COMMAND)
  351.             switch(msgid)
  352.             {
  353.             case CXCMD_DISABLE:
  354.                 Enabled=0;
  355.                 ActivateCxObj(Broker,0);
  356.                 break;
  357.  
  358.             case CXCMD_ENABLE:
  359.                 Enabled=1;
  360.                 if(!TimerPending) UpdateClk();
  361.                 ActivateCxObj(Broker,1);
  362.                 break;
  363.  
  364.             case CXCMD_KILL:
  365.             case CXCMD_UNIQUE:
  366.                 Abort=1;
  367.             }
  368.         }
  369.  
  370.         if(sig&SIGBREAKF_CTRL_C) Abort=1;
  371.     }
  372.     if(TimerPending)
  373.     {
  374.         if(!CheckIO(TimerIO)) AbortIO(TimerIO);
  375.         WaitIO(TimerIO);
  376.     }
  377.     }
  378.  
  379. cleanup:
  380.     CleanUp();
  381.  
  382.     /* Commodity stuff */
  383.     if(Broker)
  384.     {
  385.     DeleteCxObj(Broker);
  386.     while(CXMsg=(CxMsg *)GetMsg(CXPort))
  387.         ReplyMsg((struct Message *)CXMsg);
  388.     }
  389.     if(CXPort) DeleteMsgPort(CXPort);
  390.  
  391.     /* Timer stuff */
  392.     if(!TimerFail)
  393.     CloseDevice(TimerIO);
  394.     if(TimerIO) DeleteIORequest(TimerIO);
  395.     if(TimerPort) DeleteMsgPort(TimerPort);
  396.  
  397.     FreeVec(PubPat);
  398.     FreeVec(ScrPat);
  399.  
  400.     if(rdargs) FreeArgs(rdargs);
  401.     if(Do) FreeDiskObject(Do);
  402.  
  403.     CloseLocale(Locale);
  404.     CloseLibrary(LocaleBase);
  405.     CloseLibrary(IconBase);
  406.     CloseLibrary(UtilityBase);
  407.     CloseLibrary(CxBase);
  408.     CloseLibrary((struct Library *)IntuitionBase);
  409.     CloseLibrary((struct Library *)GfxBase);
  410.     CloseLibrary((struct Library *)DOSBase);
  411.  
  412. exit:
  413.     if(WBs)
  414.     {
  415.     /* Reply WBStartup */
  416.     Forbid();
  417.     ReplyMsg(WBs);
  418.     }
  419.  
  420.     MyProc->pr_Result2=0;
  421.     return 0;
  422. }
  423.  
  424. void __asm SPFunc(register __a0 struct Hook *pHook, register __a1 char pChar)
  425. {
  426.   if ((pChar&0x60) && ((int)pHook->h_Data - (int)pHook->h_SubEntry <
  427.             MAXCLOCKLEN)) /* Quick-and-dirty isprint() + */
  428.                       /* make sure that we're not */
  429.                       /* printing too many chars. */
  430.     *((*(char **)&(pHook->h_Data))++)=pChar;
  431. }
  432.  
  433. /* Print hook */
  434. struct Hook PrintHook =
  435. {
  436.   NULL, NULL,         /* MinNode */
  437.   (ULONG (* )())SPFunc,    /* h_Entry, PrintFunc */
  438.   NULL,            /* h_SubEntry. Dirtily used as pointer for */
  439.             /* where the string began. */
  440.   NULL            /* h_Data, where to put char */
  441. };
  442.  
  443. /* print date */
  444. int SPrintD(char *Dest, char *Fmt, struct DateStamp *Date)
  445. {
  446.     PrintHook.h_SubEntry=(ULONG (* )())(PrintHook.h_Data=Dest);
  447.     FormatDate(Locale,Fmt,Date,&PrintHook);
  448.     *((char *)PrintHook.h_Data)='\0';
  449.  
  450.     return ((int)((char *)PrintHook.h_Data-Dest)); /* return length of string */
  451. }
  452.  
  453. /* Display clocks on appropriate screens */
  454. static void DisplayClk(char *clkstr, int clklen, struct Screen *cs)
  455. {
  456.     if(AttemptLockLayerRom(cs->BarLayer))
  457.     {
  458.         struct DrawInfo *dri;
  459.     struct TextFont *MyFont;
  460.     int i, BltLen;
  461.     UWORD FrontPen, BackPen;
  462.     WORD dSize;
  463.  
  464.     MyFont=cs->BarLayer->rp->Font;    /* No need to 'open' it */
  465.  
  466.     if(MyBitMap->Depth<min(cs->RastPort.BitMap->Depth,8)||MyBitMap->Rows<MyFont->tf_YSize||MyBitMap->BytesPerRow<cs->RastPort.BitMap->BytesPerRow)
  467.     {
  468.         /* Need 'better' rastport */
  469.  
  470.         FreeVec(MyBitMap->Planes[0]);
  471.         InitBitMap(MyBitMap,max(MyBitMap->Depth,min(cs->RastPort.BitMap->Depth,8)),cs->Width,max(MyBitMap->Rows,MyFont->tf_YSize));
  472.  
  473.         if(!(MyBitMap->Planes[0]=AllocVec(MyBitMap->BytesPerRow*MyBitMap->Rows*MyBitMap->Depth,MEMF_CHIP)))
  474.         {
  475.         MyBitMap->Depth=0;
  476.         goto next;
  477.         }
  478.  
  479.         for(i=1;i<min(MyBitMap->Depth,8);i++)
  480.         MyBitMap->Planes[i]=((UBYTE *)MyBitMap->Planes[i-1])+MyBitMap->BytesPerRow*MyBitMap->Rows;
  481.     }
  482.  
  483.     if(dri=GetScreenDrawInfo(cs))
  484.     {
  485.         if(dri->dri_NumPens>=0x000A)
  486.         {
  487.         FrontPen=dri->dri_Pens[BARDETAILPEN];
  488.         BackPen=dri->dri_Pens[BARBLOCKPEN];
  489.         }
  490.         else
  491.         {
  492.         FrontPen=dri->dri_Pens[DETAILPEN];
  493.         BackPen=dri->dri_Pens[BLOCKPEN];
  494.         }
  495.         FreeScreenDrawInfo(cs,dri);
  496.     }
  497.     /* If we don't get DrawInfo, the pens will be somewhat random */
  498.  
  499.     SetFont(MyRPort,MyFont);
  500.     SetDrMd(MyRPort,JAM2);
  501.     SetAPen(MyRPort,FrontPen);
  502.     SetBPen(MyRPort,BackPen);
  503.     SetRast(MyRPort,BackPen);
  504.  
  505.     Move(MyRPort, MyFont->tf_XSize, MyFont->tf_Baseline);
  506.  
  507.     Text(MyRPort, clkstr, clklen);
  508.  
  509.     dSize = (cs->Flags&SCREENHIRES?HIDEPTHWIDTH:LOWDEPTHWIDTH);
  510.  
  511.     LeftEdge = cs->Width - (BltLen=MyRPort->cp_x+CLOCKOFFSET) - dSize;
  512.  
  513.     if(BltLen+dSize>cs->Width)
  514.         BltLen=cs->Width-dSize;
  515.  
  516.     ClipBlit(MyRPort,0,0,cs->BarLayer->rp,LeftEdge,1,BltLen,MyFont->tf_YSize,0x0C0);
  517. next:
  518.     UnlockLayerRom(cs->BarLayer);
  519.     }
  520. }
  521.  
  522. struct PSList
  523. {
  524.   struct PSList *psl_Next;
  525.   struct Screen *psl_Screen;
  526. };
  527.  
  528. static struct PSList *LockPubScreens(UBYTE *Pattern)
  529. {
  530.   struct PubScreenNode *psnode;
  531.   struct PSList *mylist=NULL, *tmp, *last;
  532.  
  533.   if(psnode=(struct PubScreenNode *)LockPubScreenList())
  534.     {
  535.       while((psnode=(struct PubScreenNode *)psnode->ln_Succ)->ln_Succ)
  536.     {
  537.       if(!(psnode->psn_Flags&PSNF_PRIVATE)&&MatchPattern(Pattern,psnode->ln_Name))
  538.         {
  539.           if(tmp=AllocVec(sizeof(struct PSList),0L))
  540.         {
  541.           psnode->psn_VisitorCount++;
  542.           tmp->psl_Screen=psnode->psn_Screen;
  543. #pragma msg 94 ignore push
  544.           if(mylist) last->psl_Next=tmp;
  545. #pragma msg 94 pop
  546.           else mylist=tmp;
  547.           last=tmp;
  548.         }
  549.         }
  550.     }
  551.       tmp->psl_Next=NULL;
  552.       UnlockPubScreenList();
  553.     }
  554.  
  555.   return mylist;
  556. }
  557.  
  558. static void UnlockPubScreens(struct PSList *list)
  559. {
  560.   struct PSList *tmp;
  561.   
  562.   do {
  563.     tmp=list->psl_Next;
  564.     UnlockPubScreen(NULL,list->psl_Screen);
  565.     FreeVec(list);
  566.   }
  567.   while(list=tmp);
  568. }
  569.  
  570. /* Update clock */
  571. static void UpdateClk(void)
  572. {
  573.     struct DateTime dt;
  574.     static char DispStr[MAXCLOCKLEN];
  575.     int StringLen=0;
  576.  
  577.     DateStamp(&dt);
  578.  
  579.     if(!Args[DATEFORMAT] || !LocaleBase)
  580.     {
  581.     dt.dat_Format = Fmt;
  582.     dt.dat_Flags  = 0;
  583.     dt.dat_StrDay = NULL;
  584.     dt.dat_StrDate= NULL;
  585.     dt.dat_StrTime= NULL;
  586.  
  587.     DispStr[0]='\0';
  588.  
  589.     if(Args[SHOWDAY])
  590.     {
  591.         dt.dat_StrDay = DispStr;
  592.  
  593.         DateToStr(&dt);
  594.         if(Args[SHORTDAY]) DispStr[3] = '\0';
  595.  
  596.         DispStr[StringLen=StrLen(DispStr)]=' ';
  597.         StringLen++;
  598.     }
  599.  
  600.     if(Args[SHOWDATE])
  601.     {
  602.         dt.dat_StrDay = NULL;
  603.         dt.dat_StrDate= &DispStr[StringLen];
  604.  
  605.         DateToStr(&dt);
  606.  
  607.         DispStr[StringLen=StrLen(DispStr)]=' ';
  608.         StringLen++;
  609.     }
  610.  
  611.     dt.dat_StrDate= NULL;
  612.     dt.dat_StrTime= &DispStr[StringLen];
  613.  
  614.     DateToStr(&dt);
  615.  
  616.     StringLen=StrLen(DispStr);
  617.  
  618.     if(!Args[SHOWSECS]) StringLen -= 3;
  619.     }
  620.     else
  621.     {
  622.     /* Use FormatDate */
  623.     StringLen=SPrintD(DispStr,(char *)Args[DATEFORMAT],&dt);
  624.     }
  625.  
  626.     /* Now display the things on the right screens */
  627.     {
  628.     ULONG ILock;
  629.     struct Screen *cs;
  630.  
  631.     ILock=LockIBase(0);
  632.  
  633.     /* This is part while the IntuitionBase lock is held not-quite */
  634.     /* legal. The AutoDoc says not to call any intuition, */
  635.     /* graphics, etc functions while holding the lock, but it */
  636.     /* seems to work. My guess is that the warning in the AutoDoc */
  637.     /* is to keep people from locking up the machine trying to */
  638.     /* draw while someone has a layer locked. If this is the */
  639.     /* reason, then the following should not cause any problems */
  640.     /* what so ever, since I won't draw unless I get to lock the */
  641.     /* layer. If there is some other obscure reason, then this may */
  642.     /* cause problems on some systems. But so far I haven't seen */
  643.     /* or heard of any problems with it, and it's really the only */
  644.     /* way to do what we want to do. Also, we probably hold the */
  645.     /* lock for way too long trying to draw the clock on all the */
  646.     /* right screens :-) */ 
  647.  
  648.     cs=IntuitionBase->FirstScreen;
  649.  
  650.     if(cs&&Args[FRONTSCREEN])                   /* First Screen */
  651.     {
  652.         DisplayClk(DispStr,StringLen,cs);
  653.         cs=cs->NextScreen;
  654.     }
  655.  
  656.     if(ScrPat&&cs)                          /* Match screen title */
  657.     {
  658.         do
  659.         {
  660.         if(cs->DefaultTitle&&MatchPattern(ScrPat,cs->DefaultTitle))
  661.             DisplayClk(DispStr,StringLen,cs);
  662.         }
  663.         while(cs=cs->NextScreen);
  664.     }
  665.  
  666.     UnlockIBase(ILock);
  667.  
  668.     /* Public screens */
  669.     if(PubPat)
  670.     {
  671.         if(WildPub)
  672.         {
  673.         struct PSList *pslist, *psl;
  674.  
  675.         if(psl=pslist=LockPubScreens(PubPat)) {
  676.           do {
  677.             DisplayClk(DispStr,StringLen,pslist->psl_Screen);
  678.           }
  679.           while(pslist=pslist->psl_Next);
  680.         }
  681.  
  682.         UnlockPubScreens(psl);
  683.         }
  684.         else
  685.         {
  686.         if(cs=LockPubScreen((char *)Args[PUBSCREEN]))
  687.         {
  688.             DisplayClk(DispStr,StringLen,cs);
  689.             UnlockPubScreen(NULL,cs);
  690.         }
  691.         }
  692.     }
  693.  
  694.     /* Default public screen */
  695.     if(Args[DEFSCREEN]&&(cs=LockPubScreen(NULL)))
  696.     {
  697.         DisplayClk(DispStr,StringLen,cs);
  698.         UnlockPubScreen(NULL,cs);
  699.     }
  700.     }
  701.  
  702.     /* Rescheduele timer */
  703.     GetSysTime(&TimerIO->tr_time);
  704.  
  705.     TimerIO->tr_time.tv_secs+=*(int *)Args[UPDATE];
  706.     TimerIO->tr_time.tv_micro=0;
  707.     SendIO(TimerIO);
  708.     TimerPending++;
  709. }
  710.  
  711. static void CleanUp(void)
  712. {
  713.     if(MyBitMap)
  714.     {
  715.     FreeVec(MyBitMap->Planes[0]);
  716.     FreeVec(MyBitMap);
  717.     }
  718.     FreeVec(MyRPort);
  719. }
  720.  
  721. static int StrLen(const char *str)
  722. {
  723.     int i;
  724.  
  725.     for(i=0;str[i];i++);
  726.  
  727.     return (i);
  728. }
  729.